package com.iwhalecloud.bss.kite.cucc.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * <p>
 * Description: 时间以及时间格式相关的处理功能
 * </p>
 * <p>
 * Copyright 2006 ZTEsoft Corp.
 * </p>
 *
 * @Create Date : 2006-4-19
 * @Version : 1.0
 */
public class DateFormatUtils {

    // 系统默认日期时间格式
    public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_MINUTE_FORMAT = "yyyy-MM-dd HH:mm";

    // 系统默认日期格式
    public static final String DATE_FORMAT = "yyyy-MM-dd";

    // 8位日期格式
    public static final String DATE_FORMAT_8 = "yyyyMMdd";

    // 14位日期时间格式
    public static final String DATE_TIME_FORMAT_14 = "yyyyMMddHHmmss";

    // 12位日期格式
    public static final String DATE_TIME_FORMAT_12 = "yyMMddHHmmss";
    private static final Logger LOGGER = LoggerFactory.getLogger(DateFormatUtils.class);
    /**
     * 得到应用服务器当前日期，以默认格式显示。
     *
     * @return
     */
    public static String getFormatedDate() {
        Date date = getCurrentDate();
        SimpleDateFormat dateFormator = new SimpleDateFormat(DATE_FORMAT);
        return dateFormator.format(date);

    }

    /**
     * 根据参数获取时间
     * @param num
     * @param dateFormat
     * @return
     */
    public static String getDateByParams(int num, String dateFormat) {
        Date date = getCurrentDate();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //调整日期.正数往后推,负数往前移动(1:表示明天、-1：表示昨天，0：表示今天)
        calendar.add(Calendar.DATE,num);
        date=calendar.getTime();
        SimpleDateFormat dateFormator = new SimpleDateFormat(dateFormat);
        return dateFormator.format(date);

    }

    /**
     * 得到应用服务器当前日期时间，以默认格式显示。
     *
     * @return
     */
    public static String getFormatedDateTime() {

        Date date = getCurrentDate();
        SimpleDateFormat dateFormator = new SimpleDateFormat(DATE_TIME_FORMAT);
        return dateFormator.format(date);

    }

    /**
     * 得到应用服务器的当前时间
     *
     * @return
     */
    public static Date getCurrentDate() {
        return new Date(System.currentTimeMillis());
    }

    /**
     * 得到应用服务器的当前时间，毫秒。
     *
     * @return
     */
    public static long getCurrentTimeMillis() {
        return System.currentTimeMillis();
    }

    /**
     * 得到应用服务器当前日期 按照指定的格式返回。
     *
     * @param pattern 格式类型，通过系统常量中定义，如：CrmConstants.DATE_FORMAT_8
     * @return
     */
    public static String formatDate(String pattern) {

        Date date = new Date();
        SimpleDateFormat dateFormator = new SimpleDateFormat(pattern);
        String str = dateFormator.format(date);

        return str;
    }

    /**
     * 转换输入日期 按照指定的格式返回。
     *
     * @param date
     * @param pattern 格式类型，通过系统常量中定义，如：CrmConstants.DATE_FORMAT_8
     * @return
     */
    public static String formatDate(Date date, String pattern) {

        if (date == null) {
            return "";
        }
        SimpleDateFormat dateFormator = new SimpleDateFormat(pattern);
        String str = dateFormator.format(date);

        return str;
    }

    /**
     * 转换输入日期 按照指定的格式返回。
     *
     * @param date
     * @param pattern 格式类型，通过系统常量中定义，如：CrmConstants.DATE_FORMAT_8
     * @param loc locale
     * @return
     */
    public static String formatDate(Date date, String pattern, Locale loc) {
        if (pattern == null || date == null) {
            return "";
        }
        String newDate = "";
        if (loc == null) {
            loc = Locale.getDefault();
        }
        if (date != null) {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern, loc);
            newDate = sdf.format(date);
        }
        return newDate;
    }

    /**
     * 将字符时间从一个格式转换成另一个格式。时间的格式，最好通过系统常量定义。 如： String dateStr = "2006-10-9 12:09:08";
     * DateFormatUtils.convertDateFormat(dateStr, CrmConstants.DATE_TIME_FORMAT, CrmConstants.DATE_FORMAT_8);
     *
     * @param dateStr
     * @param patternFrom 格式类型，通过系统常量中定义，如：CrmConstants.DATE_FORMAT_8
     * @param patternTo 格式类型，通过系统常量中定义，如：CrmConstants.DATE_FORMAT_8
     * @return
     */
    public static String convertDateFormat(String dateStr, String patternFrom, String patternTo) {

        if (dateStr == null || patternFrom == null || patternTo == null) {
            return "";
        }

        Date dateFrom = parseStrToDate(dateStr, patternFrom);
        String newDate = formatDate(dateFrom, patternTo);

        return newDate;
    }

    /**
     * local时间转换成UTC时间
     *
     * @param localDateStr
     * @param localFormate
     * @param utcFormate
     * @return
     */
    public static String localToUTC(String localDateStr, String localFormate, String utcFormate) {
        if (StrTools.isEmpty(localDateStr)) {
            return "";
        }
        Date localDate = parseStrToDate(localDateStr, localFormate);
        Date utcDate = localToUTC(localDate);
        return formatDate(utcDate, utcFormate);
    }

    /**
     * local时间转换成UTC时间
     *
     * @param localDate
     * @return
     */
    public static Date localToUTC(Date localDate) {
        long localTimeInMillis = localDate.getTime();
        /** long时间转换成Calendar */
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(localTimeInMillis);
        /** 取得时间偏移量 */
        int zoneOffset = calendar.get(java.util.Calendar.ZONE_OFFSET);
        /** 取得夏令时差 */
        int dstOffset = calendar.get(java.util.Calendar.DST_OFFSET);
        /** 从本地时间里扣除这些差量，即可以取得UTC时间 */
        calendar.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        /** 取得的时间就是UTC标准时间 */
        Date utcDate = new Date(calendar.getTimeInMillis());
        return utcDate;
    }

    /**
     * 将时间串按照默认格式CrmConstants.DATE_FORMAT，格式化成Date。
     *
     * @param dateStr
     * @return
     */
    public static Date parseStrToDate(String dateStr) {

        if (null == dateStr || "".equals(dateStr)) {
            return null;
        }
        SimpleDateFormat dateFormator = new SimpleDateFormat(DATE_FORMAT);

        java.util.Date tDate = dateFormator.parse(dateStr, new ParsePosition(0));

        return tDate;
    }

    public static String parseDateStrToDateTimeStr(String dateStr) {

        if (null == dateStr || "".equals(dateStr)) {
            return null;
        }
        SimpleDateFormat dateFormator = new SimpleDateFormat(DATE_FORMAT);

        java.util.Date tDate = dateFormator.parse(dateStr, new ParsePosition(0));
        return formatDate(tDate, DATE_TIME_FORMAT);

    }

    /**
     * 将时间串按照默认格式CrmConstants.DATE_FORMAT，格式化成Date。
     *
     * @param dateStr
     * @return
     */
    public static Calendar parseStrToCalendar(String dateStr) {

        if (null == dateStr || "".equals(dateStr)) {
            return null;
        }
        SimpleDateFormat dateFormator = new SimpleDateFormat(DATE_FORMAT);

        java.util.Date tDate = dateFormator.parse(dateStr, new ParsePosition(0));

        Locale loc = Locale.getDefault();
        Calendar cal = new GregorianCalendar(loc);
        cal.setTime(tDate);

        return cal;
    }

    /**
     * 将时间串按照默认格式CrmConstants.DATE_TIME_FORMAT，格式化成Date。
     *
     * @param dateStr
     * @return
     */
    public static Date parseStrToDateTime(String dateStr) {

        if (null == dateStr || "".equals(dateStr)) {
            return null;
        }
        SimpleDateFormat dateFormator = new SimpleDateFormat(DATE_TIME_FORMAT);

        java.util.Date tDate = dateFormator.parse(dateStr, new ParsePosition(0));

        return tDate;
    }

    /**
     * 将时间串按照指定格式，格式化成Date。
     *
     * @param dateStr
     * @param pattern 格式类型，通过系统常量中定义，如：CrmConstants.DATE_FORMAT_8
     * @return
     */
    public static Date parseStrToDate(String dateStr, String pattern) {
        if (null == dateStr || "".equals(dateStr)) {
            return null;
        }

        SimpleDateFormat dateFormator = new SimpleDateFormat(pattern);

        java.util.Date tDate = dateFormator.parse(dateStr, new ParsePosition(0));

        return tDate;
    }

    public static Date parseDateToFormatByDb(String dataStr, String formate) {

        // String getSql = "select to_char(to_date(?,'yyyy-MM-dd HH24:mi:ss'),'yyyy-MM-dd HH24:mi:ss') from dual";
        // List params = new ArrayList();
        // params.add(dataStr);
        // String forMaStr = sqlMapExe.queryValueBySqlAndCond(getSql, params);
        Date date = DateFormatUtils.parseDateToFormat(dataStr, formate);
        return date;
    }

    private static Map dateFormatMap = null;
    static {
        if (dateFormatMap == null) {
            dateFormatMap = new HashMap();
            dateFormatMap.put(DATE_TIME_FORMAT,
                "[0-2]{1}[0-9]{1}[0-9]{1}[0-9]{1}-[0-1]?[0-9]{1}-[0-3]?[0-9]{1} [0-2]?[0-9]{1}:[0-5]?[0-9]{1}:[0-5]?[0-9]{1}"); // yyyy-mm-dd
                                                                                                                                // hh:mm:ss
            dateFormatMap.put(DATE_FORMAT, "[0-2]{1}[0-9]{1}[0-9]{1}[0-9]{1}-[0-1]?[0-9]{1}-[0-3]?[0-9]{1}"); // yyyy-mm-dd
            dateFormatMap.put(DATE_FORMAT_8, "[0-2]{1}[0-9]{1}[0-9]{1}[0-9]{1}[0-1]?[0-9]{1}[0-3]?[0-9]{1}"); // yyyymmdd
            dateFormatMap.put(DATE_TIME_FORMAT_12,
                "[0-9]{1}[0-9]{1}[0-1]?[0-9]{1}[0-3]?[0-9]{1}[0-2]?[0-9]{1}[0-5]?[0-9]{1}[0-5]?[0-9]{1}"); // yyMMddHHmmss
            dateFormatMap.put(DATE_TIME_FORMAT_14,
                "[0-2]{1}[0-9]{1}[0-9]{1}[0-9]{1}[0-1]?[0-9]{1}[0-3]?[0-9]{1}[0-2]?[0-9]{1}[0-5]?[0-9]{1}[0-5]?[0-9]{1}"); // yyyyMMddHHmmss
        }
    }

    private static String getDateFormat(String dataStr) {
        for (Iterator it = dateFormatMap.entrySet().iterator(); it.hasNext();) {
            Map.Entry map = (Map.Entry) it.next();
            String regMatch = (String) map.getValue();
            if (java.util.regex.Pattern.matches(regMatch, dataStr)) {
                return (String) map.getKey();
            }
        }
        return null;
    }

    public static Date parseDateToFormat(String dataStr, String formate) {

        // add by AyaKoizumi 101208支持格式:
        /*
         * yyyy-mm-dd hh:mi:ss; yyyy-mm-dd; yyyymmdd; yyyyMMddHHmmss; yyMMddHHmmss;
         */
        String currDateFormat = getDateFormat(dataStr);
        if (currDateFormat == null) {
            // 默认格式匹配不上才用传入的格式
            currDateFormat = formate;
        }
        SimpleDateFormat sf = new SimpleDateFormat(currDateFormat);
        try {
            return sf.parse(dataStr);
        }
        catch (ParseException e) {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            throw new RuntimeException(" 时间格式判断有误。判断的时间格式必须为以下几种" + "[yyyy-mm-dd hh:mi:ss]" + "[yyyy-mm-dd]"
                + "[yyyymmdd]" + "[yyyyMMddHHmmss]" + "[yyMMddHHmmss]" + "不能是:" + dataStr);
        }
        // SimpleDateFormat sf = new SimpleDateFormat(formate);
        // Date data = new Date();
        // try {
        // //20101116 lin 还需要继续细化判断。
        //
        // if(formate.length() > dataStr.trim().length()){
        // dataStr = dataStr+" 00:00:00";
        // if(dataStr.trim().length() > formate.length()){
        // dataStr = dataStr.replace(" 00:00:00", "");
        // throw new RuntimeException(" 时间格式判断有误。判断的时间格式必须为："+formate+"，不能是:"+dataStr);
        // }
        // }
        // data = sf.parse(dataStr);
        // } catch (ParseException e) {
        // // TODO Auto-generated catch block
        // e.printStackTrace();
        // throw new RuntimeException(" 时间格式判断有误。判断的时间格式必须为："+formate+"，不能是:"+dataStr);
        // }
        // return data;
    }

    /**
     * 按时间格式相加： 输入要相加的时间基点（字符串型或时间类型），相加的时长（整型），格式（"year"年、"month"月、"day"日、”hour“时、”minute“分、”second“秒、"week"周）
     * 输出相加后的时间（字符串型或时间类型）
     *
     * @param dateStr
     * @param pattern
     * @param step
     * @param type "year"年、"month"月、"day"日、”hour“时、”minute“分、”second“秒、"week"周 通过常量DateFormatUtils.YEAR等来设置.
     * @return
     */
    public static String addDate(String dateStr, String pattern, int step, String type) {
        if (dateStr == null) {
            return dateStr;
        }
        else {
            Date date1 = DateFormatUtils.parseDateToFormatByDb(dateStr, pattern);

            Locale loc = Locale.getDefault();
            Calendar cal = new GregorianCalendar(loc);
            cal.setTime(date1);

            if (DateFormatUtils.WEEK.equals(type)) {

                cal.add(Calendar.WEEK_OF_MONTH, step);

            }
            else if (DateFormatUtils.YEAR.equals(type)) {

                cal.add(Calendar.YEAR, step);

            }
            else if (DateFormatUtils.MONTH.equals(type)) {

                cal.add(Calendar.MONTH, step);

            }
            else if (DateFormatUtils.DAY.equals(type)) {

                cal.add(Calendar.DAY_OF_MONTH, step);

            }
            else if (DateFormatUtils.HOUR.equals(type)) {

                cal.add(Calendar.HOUR, step);

            }
            else if (DateFormatUtils.MINUTE.equals(type)) {

                cal.add(Calendar.MINUTE, step);

            }
            else if (DateFormatUtils.SECOND.equals(type)) {

                cal.add(Calendar.SECOND, step);

            }

            return DateFormatUtils.formatDate(cal.getTime(), pattern);
        }
    }

    /**
     * 按时间格式相减： 输入要相加的时间基点（字符串型或时间类型），相加的时长（整型），格式（"year"年、"month"月、"day"日、”hour“时、”minute“分、”second“秒、"week"周）
     * 输出相加后的时间（字符串型或时间类型）
     *
     * @param dateStr
     * @param pattern
     * @param step
     * @param type "year"年、"month"月、"day"日、”hour“时、”minute“分、”second“秒、"week"周
     * @return
     */
    public static String minusDate(String dateStr, String pattern, int step, String type) {

        return addDate(dateStr, pattern, (0 - step), type);

    }

    /**
     * 日期增加天数
     *
     * @param date
     * @param days
     * @return
     */
    public static Date addDay(Date date, int days) {
        if (date == null) {
            return date;
        }
        else {
            Locale loc = Locale.getDefault();
            Calendar cal = new GregorianCalendar(loc);
            cal.setTime(date);
            cal.add(Calendar.DAY_OF_MONTH, days);
            return cal.getTime();
        }
    }

    /**
     * 获取两个日期之差
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getDays(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return 0;
        }
        else {
            return (int) ((date2.getTime() - date1.getTime()) / 0x5265c00L); // 86400000 代表毫秒
        }
    }

    /**
     * 获取两个日期之差
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getSecs(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return 0;
        }
        else {
            return (int) ((date2.getTime() - date1.getTime()) / 1000); // 1000 代表毫秒
        }
    }

    /**
     * 获取两个日期之差
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getPoints(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return 0;
        }
        else {
            return (int) ((date2.getTime() - date1.getTime()) / (1000 * 60)); // 1000 代表毫秒
        }
    }

    /**
     * 两个日期之差（天）
     *
     * @param dateStr1
     * @param dateStr2
     * @param pattern
     * @return
     */
    public static int getDayByStrs(String dateStr1, String dateStr2, String pattern) {
        if (StrTools.isEmpty(dateStr1) || StrTools.isEmpty(dateStr2)) {
            return 0;
        }
        Date date1 = DateFormatUtils.parseDateToFormat(dateStr1, pattern);
        Date date2 = DateFormatUtils.parseDateToFormat(dateStr2, pattern);
        return getDays(date1, date2);
    }

    /**
     * 两个日期之差（分）
     *
     * @param dateStr1
     * @param dateStr2
     * @param pattern
     * @return
     */
    public static int getPoinsByStrs(String dateStr1, String dateStr2, String pattern) {
        if (StrTools.isEmpty(dateStr1) || StrTools.isEmpty(dateStr2)) {
            return 0;
        }
        Date date1 = DateFormatUtils.parseDateToFormat(dateStr1, pattern);
        Date date2 = DateFormatUtils.parseDateToFormat(dateStr2, pattern);
        return getPoints(date1, date2);
    }

    /**
     * 两个日期之差（秒）
     *
     * @param dateStr1
     * @param dateStr2
     * @param pattern
     * @return
     */
    public static int getSecByStrs(String dateStr1, String dateStr2, String pattern) {
        if (StrTools.isEmpty(dateStr1) || StrTools.isEmpty(dateStr2)) {
            return 0;
        }
        Date date1 = DateFormatUtils.parseDateToFormat(dateStr1, pattern);
        Date date2 = DateFormatUtils.parseDateToFormat(dateStr2, pattern);
        return getSecs(date1, date2);
    }



    /**
     * 日期比较大小
     *
     * @param dateStr1
     * @param dateStr2
     * @param pattern
     * @return
     */
    public static int compareDate(String dateStr1, String dateStr2, String pattern) {

        Date date1 = DateFormatUtils.parseDateToFormat(dateStr1, pattern);
        Date date2 = DateFormatUtils.parseDateToFormat(dateStr2, pattern);

        return date1.compareTo(date2);

    }

    /**
     * 日期比较大小
     *
     * @param dateStr1
     * @param dateStr2
     * @param pattern
     * @return
     */
    public static int compareDateByDb(String dateStr1, String dateStr2, String pattern) {

        Date date1 = DateFormatUtils.parseDateToFormatByDb(dateStr1, pattern);
        Date date2 = DateFormatUtils.parseDateToFormatByDb(dateStr2, pattern);

        return date1.compareTo(date2);

    }

    public static int getDayToSys(String dateStr1) {
        if (StrTools.isEmpty(dateStr1)) {
            return 0;
        }
        else {
            String sysStr = getFormatedDate();
            return getDayByStrs(sysStr, dateStr1, DATE_FORMAT);
        }
    }

    /**
     * @param dateStr
     * @param pattern
     * @return
     */
    public static String getFirstDayInMonth(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int month = cal.get(Calendar.MONTH);
        int day = cal.get(Calendar.DAY_OF_MONTH);

        cal.add(Calendar.DAY_OF_MONTH, (1 - day)); // 日期加减天数

        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    // 取当月第一天第一秒
    public static String getFirstDayFirstSecInMonth(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int day = cal.get(Calendar.DAY_OF_MONTH);
        cal.add(Calendar.DAY_OF_MONTH, (1 - day)); // 日期加减天数
        if (pattern.length() > 10) {
            cal.add(Calendar.SECOND, 1); // 再+1秒
        }
        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    // 取当天第一秒
    public static String getReferDayFirstSec(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        cal.add(Calendar.SECOND, 1); // 再+1秒
        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    // 取当天最后一秒
    public static String getReferDayLastSec(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int daySec = (60 * 60 * 24) - 1; // 一天的秒-1
        cal.add(Calendar.SECOND, daySec);
        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    /**
     * 获取当月1号
     *
     * @param dateStr
     * @param pattern
     * @author mzp
     * @time 20080717
     * @return
     */
    public static String getFirstDayInMonth(String dateStr, String pattern, String isZeroSecond) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH);
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);
        day = 1;
        hour = 0;
        minute = 0;
        second = 0;
        cal.clear();
        cal.set(year, month, day, hour, minute, second);
        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    /**
     * 获取下月1号
     *
     * @param dateStr
     * @param pattern
     * @author AyaKoizumi
     * @time 20101112
     * @return
     */
    public static String getFirstDayInNextMonth(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH);
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);
        day = 1;
        hour = 0;
        minute = 0;
        second = 0;
        cal.clear();
        cal.set(year, month + 1, day, hour, minute, second);
        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    /**
     * @param dateStr
     * @param pattern
     * @return
     */
    public static String getLastDayInMonth(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int month = cal.get(Calendar.MONTH);
        int day = cal.get(Calendar.DAY_OF_MONTH);

        int maxDayInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);

        int step = maxDayInMonth - day;

        cal.add(Calendar.DAY_OF_MONTH, step); // 当月天上再添加几天

        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    // 取当月最后一天最后一秒
    public static String getLastDayLastSecInMonth(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int day = cal.get(Calendar.DAY_OF_MONTH);

        int maxDayInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);

        int step = maxDayInMonth - day + 1;

        cal.add(Calendar.DAY_OF_MONTH, step); // 当月天上再添加几天，得到次月1号
        cal.add(Calendar.SECOND, -1); // 减1秒，得到本月最后一天最后一秒
        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    // 取上月最后一天最后一秒
    public static String getUpDayLastSecInMonth(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int day = cal.get(Calendar.DAY_OF_MONTH);

        cal.add(Calendar.DAY_OF_MONTH, -day + 1); // 当月天上再添加几天，得到次月1号
        cal.add(Calendar.SECOND, -1); // 减1秒，得到本月最后一天最后一秒
        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    /**
     * @param dateStr
     * @param pattern
     * @return
     */
    public static String getFirstDayInWeek(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int day = cal.get(Calendar.DAY_OF_WEEK);

        cal.add(Calendar.DAY_OF_MONTH, (1 - day));

        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    /**
     * @param dateStr
     * @param pattern
     * @return
     */
    public static String getLastDayInWeek(String dateStr, String pattern) {
        Calendar cal = DateFormatUtils.parseStrToCalendar(dateStr);
        int day = cal.get(Calendar.DAY_OF_WEEK);

        cal.add(Calendar.DAY_OF_MONTH, (6 - day));

        return DateFormatUtils.formatDate(cal.getTime(), pattern);
    }

    public static long calendarDayPlus(String dateStr1, String dateStr2) {

        if (dateStr1 == null || dateStr2 == null || "".equals(dateStr1) || "".equals(dateStr2)) {
            return 0;
        }
        Date date1 = DateFormatUtils.parseStrToDate(dateStr1);
        Date date2 = DateFormatUtils.parseStrToDate(dateStr2);
        Calendar c1 = Calendar.getInstance();
        c1.setTime(date1);
        Calendar c2 = Calendar.getInstance();
        c2.setTime(date2);
        long t1 = c1.getTimeInMillis();
        long t2 = c2.getTimeInMillis();
        long day = (t2 - t1) / (1000 * 60 * 60 * 24);
        return day;
    }

    /**
     * @param dateStr1
     * @param dateStr2
     * @return
     */
    public static int calendarPlus(String dateStr1, String dateStr2) {

        if (dateStr1 == null || dateStr2 == null || "".equals(dateStr1) || "".equals(dateStr2)) {
            return 0;
        }

        Calendar cal1 = DateFormatUtils.parseStrToCalendar(dateStr1);

        Calendar cal2 = DateFormatUtils.parseStrToCalendar(dateStr2);

        int dataStr1Year = cal1.get(Calendar.YEAR);
        int dataStr2Year = cal2.get(Calendar.YEAR);

        int dataStr1Month = cal1.get(Calendar.MONTH);
        int dataStr2Month = cal2.get(Calendar.MONTH);

        return ((dataStr2Year * 12 + dataStr2Month + 1) - (dataStr1Year * 12 + dataStr1Month));

    }

    /**
     * 从当前时间获取N个工作日
     *
     * @param days 为负数时代表获取当前时间之前的具体工作日；为正数时代表获取当前时间之后的具体工作日
     * @return
     */
    public static Date getWorkDateFromNow(int days) {
        Date curDate = new Date();
        if (days == 0) {
            return curDate;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(curDate);
        // 控制向前还是向后
        boolean position = days > 0 ? true : false;
        int size = Math.abs(days);
        while (size > 0) {
            if (position) {
                cal.add(Calendar.DATE, 1);
            }
            else {
                cal.add(Calendar.DATE, -1);
            }
            if (isWeekend(cal)) {
                continue;
            }
            size--;
        }
        return cal.getTime();
    }

    /**
     * 是否为周末
     *
     * @param cal
     * @return
     */
    public static boolean isWeekend(Calendar cal) {
        if (cal != null) {
            if ((cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
                || (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 兼容时间不同格式
     *
     * @param dateStr
     * @return
     */
    public static String compatibleTime(String dateStr) {

        String expDateFormat = "";
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        if (StrTools.isEmpty(dateStr)) {
            return expDateFormat;
        }
        // 失效时间兼容不同格式
        if (java.util.regex.Pattern.matches(DATE_TIME_FORMAT_NO_CHANGE, dateStr)) {
            expDateFormat = dateStr;
        }
        else {
            if (java.util.regex.Pattern.matches(DATE_TIME_FORMAT_ONE, dateStr)) {
                LocalDateTime localDateTime = LocalDateTime.parse(dateStr);
                expDateFormat = localDateTime.format(df);
            }
            else if (java.util.regex.Pattern.matches(DATE_TIME_FORMAT_TWO, dateStr)) {
                LocalDateTime localDateTime = LocalDateTime.parse(dateStr);
                expDateFormat = localDateTime.format(df);
            }
        }

        // 时间错误,无法解析，不处理
        return expDateFormat;
    }

 // 获得本周一与当前日期相差的天数
    public static  int getMondayPlus() {
        Calendar cd = Calendar.getInstance();
        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 1) {
            return -6;
        } else {
            return 2 - dayOfWeek;
        }
    }

    // 获得当前周- 周一的日期
    public static String getCurrentMonday() {
        int mondayPlus = getMondayPlus();
        GregorianCalendar currentDate = new GregorianCalendar();
        currentDate.add(GregorianCalendar.DATE, mondayPlus);
        Date monday = currentDate.getTime();
        SimpleDateFormat df = new SimpleDateFormat(DateFormatUtils.DATE_FORMAT);
        String preMonday = df.format(monday) + " 00:00:00";
        return preMonday;
    }

    // 获得当前周- 周日  的日期
    public static String getPreviousSunday() {
        int mondayPlus = getMondayPlus();
        GregorianCalendar currentDate = new GregorianCalendar();
        currentDate.add(GregorianCalendar.DATE, mondayPlus +6);
        Date monday = currentDate.getTime();
        SimpleDateFormat df = new SimpleDateFormat(DateFormatUtils.DATE_FORMAT);
        String preMonday = df.format(monday) + " 23:59:59";
        return preMonday;
    }

    // 获得当前月--开始日期
    public static String getMinMonthDate() {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat df = new SimpleDateFormat(DateFormatUtils.DATE_FORMAT);
        try {
            calendar.setTime(df.parse(DateFormatUtils.getFormatedDateTime()));
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
            return df.format(calendar.getTime()) + " 00:00:00";
        } catch (java.text.ParseException e) {
            LOGGER.error(e.getMessage());
        }
        return null;
    }

    /**
     * 获取下个月月初第一天
     * @return
     */
    public static String getMinNextMonthDate() {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat df = new SimpleDateFormat(DateFormatUtils.DATE_FORMAT);
        try {
            calendar.setTime(df.parse(DateFormatUtils.getFormatedDateTime()));
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
            calendar.add(Calendar.MONTH, 1);
            return df.format(calendar.getTime()) + " 00:00:00";
        } catch (java.text.ParseException e) {
            LOGGER.error(e.getMessage());
        }
        return null;
    }

    /**
     * 获取前一天最大时间
     * @return
     */
    public static String getEndOfLastDay() {
        Calendar calendarEnd = Calendar.getInstance();
        SimpleDateFormat df = new SimpleDateFormat(DateFormatUtils.DATE_TIME_FORMAT);
        calendarEnd.setTime(new Date());
        calendarEnd.add(Calendar.DATE, -1);
        calendarEnd.set(Calendar.HOUR_OF_DAY, 23);
        calendarEnd.set(Calendar.MINUTE, 59);
        calendarEnd.set(Calendar.SECOND, 59);
        calendarEnd.set(Calendar.MILLISECOND, 0);
        return df.format(calendarEnd.getTime());
    }

    // 获得当前月--结束日期
    public static String getMaxMonthDate(){
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat df = new SimpleDateFormat(DateFormatUtils.DATE_FORMAT);
        try {
            calendar.setTime(df.parse(DateFormatUtils.getFormatedDateTime()));
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
            return df.format(calendar.getTime()) + " 23:59:59";
        }  catch (java.text.ParseException e) {
            LOGGER.error(e.getMessage());
        }
        return null;
    }

    /**
     * Description: 获取某天最小时间<br>
     *
     * @author tengg<br>
     * @taskId <br>
     * @param date
     * @return <br>
     */
    public static Date getStartOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()),
                ZoneId.systemDefault());
        LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
        return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * Description: 获取某天最大时间<br>
     *
     * @author tengg<br>
     * @taskId <br>
     * @param date
     * @return <br>
     */
    public static Date getEndOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()),
                ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * Description: 当前时间向前活向后加几个工作日,周六和周日不包括在内<br>
     *
     * @author tengg<br>
     * @taskId <br>
     * @param date
     * @param businessDays
     * @return <br>
     */
    public static String businessDaysFrom(Date date, int businessDays) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        for (int i = 0; i < Math.abs(businessDays);) {
            calendar.add(Calendar.DAY_OF_MONTH, businessDays > 0 ? 1 : -1);
            if (!NON_BUSINESS_DAYS.contains(calendar.get(Calendar.DAY_OF_WEEK))){
                i++;
            }
        }

        return formatDate(calendar.getTime(), DATE_TIME_FORMAT);
    }
    /**
     * Description: 当前时间向前活向后加几个工作日,周六和周日不包括在内<br>
     *
     * @author tengg<br>
     * @taskId <br>
     * @param date
     * @param businessDays
     * @return <br>
     */
    public static String businessDaysMinute(Date date, int businessDays) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        for (int i = 0; i < Math.abs(businessDays);) {
            calendar.add(Calendar.DAY_OF_MONTH, businessDays > 0 ? 1 : -1);
            if (!NON_BUSINESS_DAYS.contains(calendar.get(Calendar.DAY_OF_WEEK))){
                i++;
            }
        }

        return formatDate(calendar.getTime(), DATE_MINUTE_FORMAT);
    }

    /**
     * 根据属性attrValueTypeId，获取对应的时间格式
     * @author zhang.song
     * @date 2022-04-01 15:24
     * @param attrType
     * @return java.lang.String
     */
    public static String getDateFormatTypeByAttrType(String attrType) {
        String dateFormatType;
        switch (attrType) {
            case "98D":
                dateFormatType = DATE_FORMAT;
                break;
            case "98L":
                dateFormatType = DATE_MINUTE_FORMAT;
                break;
            case "98O":
                dateFormatType = DATE_TIME_FORMAT;
                break;
            default:
                dateFormatType = DATE_FORMAT;
                break;
        }
        return dateFormatType;
    }

    private static final List<Integer> NON_BUSINESS_DAYS = Arrays.asList(
        Calendar.SATURDAY,
        Calendar.SUNDAY
    );

    public static final String YEAR = "year";

    public static final String MONTH = "month";

    public static final String DAY = "day";

    public static final String HOUR = "hour";

    public static final String MINUTE = "minute";

    public static final String SECOND = "second";

    public static final String WEEK = "week";

    public static final String DATE = "yyyy-MM-dd";

    public static final String TIME = "yyyy-MM-dd HH24:mi:ss";

    // add by liursh 2012.3.28
    public static final String DEFAULTPATTERN = "yyyy-MM-dd HH:mm:ss";

    private static final String DATE_TIME_FORMAT_ONE = "[0-9]{4}-[0-1]?[0-9]{1}-[0-3]?[0-9]{1}T[0-5]?[0-9]{1}:[0-5]?[0-9]{1}:[0-5]?[0-9]{1}";

    private static final String DATE_TIME_FORMAT_TWO = "[0-9]{4}-[0-1]?[0-9]{1}-[0-3]?[0-9]{1}T[0-5]?[0-9]{1}:[0-5]?[0-9]{1}";

    private static final String DATE_TIME_FORMAT_NO_CHANGE = "[0-9]{4}-[0-1]?[0-9]{1}-[0-3]?[0-9]{1} [0-5]?[0-9]{1}:[0-5]?[0-9]{1}:[0-5]?[0-9]{1}";
}
